package com.shelpe.services.scheduler;

import java.util.Date;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.JobParametersInvalidException;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
import org.springframework.batch.core.repository.JobRestartException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import com.shelpe.services.scheduler.dto.RptKeywordDto;
import com.shelpe.services.scheduler.dto.UserSchedulerDto;
import com.shelpe.services.scheduler.po.Adgroups;
import com.shelpe.services.scheduler.po.Campaigns;
import com.shelpe.services.scheduler.po.Users;
import com.shelpe.services.scheduler.repository.AdgroupsRepository;
import com.shelpe.services.scheduler.repository.CampaignsRepository;
import com.shelpe.services.scheduler.repository.UsersRepository;
import com.shelpe.services.scheduler.syncclient.KeywordClient;
import com.shelpe.services.scheduler.util.Util;


@RestController
@RequestMapping(value="/simbascheduler")
public class DataSyncController {
	
	private static final Logger logger = LoggerFactory.getLogger(DataSyncController.class);
	
	@Autowired 
	@Qualifier("asyncJobLauncher")
	private JobLauncher jobLauncherAsync;
	
	@Autowired 
	@Qualifier("jobLauncher")
	private JobLauncher jobLauncher;
	 
	 @Autowired
	 @Qualifier("syncSingleUserBaseData")//1
	 private Job syncSingleUserBaseData;
	 
	 @Autowired
	 @Qualifier("syncSingleUserRptAdgroupData")//2
	 private Job syncSingleUserRptAdgroupData;
	 
	 @Autowired
	 @Qualifier("syncSingleUserCreativeData")//3
	 private Job syncSingleUserCreativeData;
	 
	 @Autowired
	 @Qualifier("syncSingleUserRptCreativeData")//4
	 private Job syncSingleUserRptCreativeData;
	 
	 @Autowired
	 @Qualifier("syncSingleUserKeywordData")//5
	 private Job syncSingleUserKeywordData;
	 
	 @Autowired
	 @Qualifier("syncSingleUserRptKeywordData")//6
	 private Job syncSingleUserRptKeywordData;
	 
	 @Autowired
	 @Qualifier("syncSingleUserRptCustomerData")//6
	 private Job syncSingleUserRptCustomerData;
	 
	 @Autowired
	 @Qualifier("syncSingleUserRptCampaignData")//6
	 private Job syncSingleUserRptCampaignData;
	 
	
	 @Value("${simbaschedule.mainInnerUserId}")
	 private String mainInnerUserId;
	 
	 @Autowired
	 private UsersRepository userRep;
	 
	 @Autowired
	 private AdgroupsRepository adRep;
	 
	 @Autowired
	 private CampaignsRepository camRep;
	 
	 @Autowired
	 private KeywordClient keyWordClient;
	 
	 private JobParametersBuilder jobParametersBuilder = new JobParametersBuilder(); 
	 
	 private final ExecutorService executor = Executors.newFixedThreadPool(2);
	 
	 
	@RequestMapping("/tenants/{user}")
	@ResponseBody
	public UserSchedulerDto syncUserJob(@PathVariable("user") final String user){	
		
		CompletionService<UserSchedulerDto> comletionService = new ExecutorCompletionService<UserSchedulerDto>(executor); 
		
		boolean isNumber = user.matches("-?[0-9]+.*[0-9]*");
		Long userId = null;
		final UserSchedulerDto dto = new UserSchedulerDto();
		
    	if(isNumber){
    		userId = Long.valueOf(user);
    	}else{
    		List<Users> users = userRep.findByNick(user);
    		dto.setNick(user);
    		if(users != null && users.size() > 0){
    			userId = users.iterator().next().getUserId();
    		}
    	}
    	
    	dto.setUserId(userId);
    	if(userId == null){
    		logger.warn("syncUserJob userId {}", userId);
    		dto.setMessage("Failed");
    		return dto;
    	}
    	
    	logger.info(">>>syncUserJob userId {} begin", userId);
		
		final Long finalUserId = userId;
		
		comletionService.submit(new Callable<UserSchedulerDto>(){

			@Override
			public UserSchedulerDto call() throws Exception {
				// TODO Auto-generated method stub
		    	
		    	long pages = 1;
		    	long total = userRep.count();
		    	long pageSize = Util.computePageSize(total, pages);
		    	
		    	
		    	JobParameters jobParams = jobParametersBuilder.addDate("scheduleTime", new Date())
		    			.addLong("index", 1L)
		  				.addLong("pageNo", 0L)
		  				.addLong("pageSize", pageSize)
						.addLong("subIndex", 0L)
						.addLong("subPages", 1L)
						.addLong("userId", finalUserId)
						.addString("mainInnerUserId", mainInnerUserId)
						.toJobParameters();
				 		
			 	try {
			 		
			 		jobLauncher.run(syncSingleUserBaseData, jobParams);
			 		
				} catch (JobExecutionAlreadyRunningException | JobRestartException | JobInstanceAlreadyCompleteException
						| JobParametersInvalidException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			 	logger.info(">>>syncUserJob userId {} end of syncSingleUserBaseData", finalUserId);
			 	
			 	Date scheduleTime = new Date();
		    	List<Campaigns> camList = camRep.findByUserId(finalUserId);
		    	total = 0;
		    	
		    	if(camList != null && camList.size() > 0){
		    		total = camList.size();
		    	}
		    	logger.info(">>>syncUserJob userId {}, campagin num {}",finalUserId, total);
		    	long pageSizeCam = Util.computePageSize(total, pages);
		    	
		    	List<Adgroups> adList = adRep.findByUserId(finalUserId);
		    	total = 0;
		    	
		    	if(adList != null && adList.size() > 0){
		    		total = adList.size();
		    	}
		    	logger.info(">>>syncUserJob userId {}, adgroup num {}",finalUserId, total);
		    	long pageSizeAd = Util.computePageSize(total, pages);
		    		
		    	JobParameters jobParams1 = jobParametersBuilder.addDate("scheduleTime", scheduleTime)
		    				.addLong("index", 2L)
		      				.addLong("pageNo", 0L)
		      				.addLong("pageSize", pageSizeCam)
							.addLong("subIndex", 0L)
							.addLong("subPages", 1L)
		    				.addLong("userId", finalUserId)
		    				.addString("mainInnerUserId", mainInnerUserId)
		    				.toJobParameters();
		    	JobParameters jobParams2 = jobParametersBuilder.addDate("scheduleTime", scheduleTime)
		    				.addLong("index", 3L)
		      				.addLong("pageNo", 0L)
		      				.addLong("pageSize", pageSizeAd)
							.addLong("subIndex", 0L)
							.addLong("subPages", 1L)
		    				.addLong("userId", finalUserId)
		    				.addString("mainInnerUserId", mainInnerUserId)
		    				.toJobParameters();
		    	JobParameters jobParams3 = jobParametersBuilder.addDate("scheduleTime", scheduleTime)
		    				.addLong("index", 4L)
		      				.addLong("pageNo", 0L)
		      				.addLong("pageSize", pageSizeAd)
							.addLong("subIndex", 0L)
							.addLong("subPages", 1L)
		    				.addLong("userId", finalUserId)
		    				.addString("mainInnerUserId", mainInnerUserId)
		    				.toJobParameters();
		    	JobParameters jobParams4 = jobParametersBuilder.addDate("scheduleTime", scheduleTime)
		    				.addLong("index", 5L)
		      				.addLong("pageNo", 0L)
		      				.addLong("pageSize", pageSizeAd)
							.addLong("subIndex", 0L)
							.addLong("subPages", 1L)
		    				.addLong("userId", finalUserId)
		    				.addString("mainInnerUserId", mainInnerUserId)
		    				.toJobParameters();
		    	JobParameters jobParams5 = jobParametersBuilder.addDate("scheduleTime", scheduleTime)
		    				.addLong("index", 6L)
		      				.addLong("pageNo", 0L)
		      				.addLong("pageSize", pageSizeAd)
							.addLong("subIndex", 0L)
							.addLong("subPages", 1L)
		    				.addLong("userId", finalUserId)
		    				.addString("mainInnerUserId", mainInnerUserId)
		    				.toJobParameters();
		    		 		
		    	 	try {
		    	 		
		    	 		jobLauncherAsync.run(syncSingleUserRptAdgroupData, jobParams1);
		    	 		jobLauncherAsync.run(syncSingleUserCreativeData, jobParams2);
		    	 		jobLauncherAsync.run(syncSingleUserRptCreativeData, jobParams3);
		    	 		jobLauncherAsync.run(syncSingleUserKeywordData, jobParams4);
		    	 		jobLauncherAsync.run(syncSingleUserRptKeywordData, jobParams5);
		    	 		
		    		} catch (JobExecutionAlreadyRunningException | JobRestartException | JobInstanceAlreadyCompleteException
		    				| JobParametersInvalidException e) {
		    			// TODO Auto-generated catch block
		    			e.printStackTrace();
		    		}
		    		
		    	
		    	logger.info(">>>syncUserJob userId {} out", finalUserId);
		    	//result.setResult(dto);
		    	
		    	return dto;
			}
			
		});
		
		return dto;
	}
	
	@RequestMapping("/tenants/{user}/@needsyncrpt")	
	@ResponseBody
	public UserSchedulerDto isNeedSyncUserRpt(@PathVariable("user") final String user){
		
		boolean isNumber = user.matches("-?[0-9]+.*[0-9]*");
		Long userId = null;
		final UserSchedulerDto dto = new UserSchedulerDto();
		
    	if(isNumber){
    		userId = Long.valueOf(user);
    	}else{
    		List<Users> users = userRep.findByNick(user);
    		dto.setNick(user);
    		if(users != null && users.size() > 0){
    			userId = users.iterator().next().getUserId();
    		}
    	}
    	
    	dto.setUserId(userId);
    	if(userId == null){
    		logger.warn("syncUserJob userId {}", userId);
    		dto.setMessage("Failed");
    		return dto;
    	}
    	
    	RptKeywordDto rptDto = keyWordClient.isNeedSyncRptKeywordsByUser(userId);
    	
    	dto.setNeedSync(rptDto.isNeedSync());
    	
    	return dto;
	}
	 
	@RequestMapping("/tenants/{user}/@syncrpt")
	@ResponseBody
	public UserSchedulerDto syncUserRpt(@PathVariable("user") final String user){
		
		CompletionService<UserSchedulerDto> comletionService = new ExecutorCompletionService<UserSchedulerDto>(executor); 
		
		boolean isNumber = user.matches("-?[0-9]+.*[0-9]*");
		Long userId = null;
		final UserSchedulerDto dto = new UserSchedulerDto();
		
    	if(isNumber){
    		userId = Long.valueOf(user);
    	}else{
    		List<Users> users = userRep.findByNick(user);
    		dto.setNick(user);
    		if(users != null && users.size() > 0){
    			userId = users.iterator().next().getUserId();
    		}
    	}
    	
    	dto.setUserId(userId);
    	if(userId == null){
    		logger.warn("syncUserJob userId {}", userId);
    		dto.setMessage("Failed");
    		return dto;
    	}
    	
    	logger.info(">>>syncUserRpt userId {} begin", userId);
		
		final Long finalUserId = userId;
		
		comletionService.submit(new Callable<UserSchedulerDto>(){

			@Override
			public UserSchedulerDto call() throws Exception {
				// TODO Auto-generated method stub
		    	
		    	long pages = 1;
		    	long total = userRep.count();
		    	long pageSize = Util.computePageSize(total, pages);
		    	
		    	
		    	JobParameters jobParams = jobParametersBuilder.addDate("scheduleTime", new Date())
		    			.addLong("index", 1L)
		  				.addLong("pageNo", 0L)
		  				.addLong("pageSize", pageSize)
						.addLong("subIndex", 0L)
						.addLong("subPages", 1L)
						.addLong("userId", finalUserId)
						.addString("mainInnerUserId", mainInnerUserId)
						.toJobParameters();
				 
		    	JobParameters jobParams1 = jobParametersBuilder.addDate("scheduleTime", new Date())
		    			.addLong("index", 2L)
		  				.addLong("pageNo", 0L)
		  				.addLong("pageSize", pageSize)
						.addLong("subIndex", 0L)
						.addLong("subPages", 1L)
						.addLong("userId", finalUserId)
						.addString("mainInnerUserId", mainInnerUserId)
						.toJobParameters();
		    	
			 	Date scheduleTime = new Date();
		    	List<Campaigns> camList = camRep.findByUserId(finalUserId);
		    	total = 0;
		    	
		    	if(camList != null && camList.size() > 0){
		    		total = camList.size();
		    	}
		    	logger.info(">>>syncUserRpt userId {}, campaign num {}", finalUserId, total);
		    	long pageSizeCam = Util.computePageSize(total, pages);
		    	
		    	JobParameters jobParams2 = jobParametersBuilder.addDate("scheduleTime", scheduleTime)
	    				.addLong("index", 3L)
	      				.addLong("pageNo", 0L)
	      				.addLong("pageSize", pageSizeCam)
						.addLong("subIndex", 0L)
						.addLong("subPages", 1L)
	    				.addLong("userId", finalUserId)
	    				.addString("mainInnerUserId", mainInnerUserId)
	    				.toJobParameters();
		    	
			 	try {
			 		
			 		jobLauncher.run(syncSingleUserRptCustomerData, jobParams);
			 		jobLauncher.run(syncSingleUserRptCampaignData, jobParams1);
			 		jobLauncher.run(syncSingleUserRptAdgroupData, jobParams2);
			 		
				} catch (JobExecutionAlreadyRunningException | JobRestartException | JobInstanceAlreadyCompleteException
						| JobParametersInvalidException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			 
		    	
		    	List<Adgroups> adList = adRep.findByUserId(finalUserId);
		    	total = 0;
		    	
		    	if(adList != null && adList.size() > 0){
		    		total = adList.size();
		    	}
		    	logger.info(">>>syncUserRpt userId {}, adgroup num {}", finalUserId, total);
		    	long pageSizeAd = Util.computePageSize(total, pages);
		    		

		    	JobParameters jobParams3 = jobParametersBuilder.addDate("scheduleTime", scheduleTime)
		    				.addLong("index", 4L)
		      				.addLong("pageNo", 0L)
		      				.addLong("pageSize", pageSizeAd)
							.addLong("subIndex", 0L)
							.addLong("subPages", 1L)
		    				.addLong("userId", finalUserId)
		    				.addString("mainInnerUserId", mainInnerUserId)
		    				.toJobParameters();
		    	JobParameters jobParams4 = jobParametersBuilder.addDate("scheduleTime", scheduleTime)
		    				.addLong("index", 5L)
		      				.addLong("pageNo", 0L)
		      				.addLong("pageSize", pageSizeAd)
							.addLong("subIndex", 0L)
							.addLong("subPages", 1L)
		    				.addLong("userId", finalUserId)
		    				.addString("mainInnerUserId", mainInnerUserId)
		    				.toJobParameters();
		    		 		
		    	 	try {
		    	 		
		    	 		jobLauncherAsync.run(syncSingleUserRptCreativeData, jobParams3);
		    	 		jobLauncherAsync.run(syncSingleUserRptKeywordData, jobParams4);
		    	 		
		    		} catch (JobExecutionAlreadyRunningException | JobRestartException | JobInstanceAlreadyCompleteException
		    				| JobParametersInvalidException e) {
		    			// TODO Auto-generated catch block
		    			e.printStackTrace();
		    		}
		    		
		    	
		    	logger.info(">>>syncUserRpt userId {} out", finalUserId);
		    	//result.setResult(dto);
		    	
		    	return dto;
			}
			
		});
		
		return dto;
		
	}


}
